package pers.duorhs.easierfeign.config;

import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import pers.duorhs.easierfeign.iface.GeneralRemoteController;
import pers.duorhs.easierfeign.invoker.EasierFeignServiceInvoker;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;

/**
 * @author Duorhs
 * @date 2022/1/18 11:34
 */
@Configuration
@AutoConfigureAfter(EasierFeignProviderConfiguration.class)
@ConditionalOnProperty(prefix = "easierfeign", name = "isProvider", havingValue = "true")
public class EasierFeignControllerMaker {


    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    @Resource
    private EasierFeignProperties.ControllerProperties controllerProperties;

    @Autowired
    private EasierFeignServiceInvoker invoker;

    /**
     * 动态生成controller
     */
    @SneakyThrows
    @PostConstruct
    private void createController() {

        String prefix = controllerProperties.getPrefix();
        GeneralRemoteController controller = new GeneralRemoteController(invoker);
        Method remoteInvoke = controller.getClass().getDeclaredMethod("remoteInvoke", String.class, String.class, String.class);
        PostMapping postMapping = remoteInvoke.getDeclaredAnnotation(PostMapping.class);
        InvocationHandler h = Proxy.getInvocationHandler(postMapping);
        Field memberValues = h.getClass().getDeclaredField("memberValues");
        memberValues.setAccessible(true);
        Map<String, Object> map = (Map) memberValues.get(h);
        String[] urls = (String[]) map.get("value");
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < urls.length; i++) {
            urls[i] = sb.append(prefix).append("/").append(urls[i]).toString();
        }
        map.put("value", urls);

        Method getMappingForMethod = RequestMappingHandlerMapping.class.getDeclaredMethod("getMappingForMethod", Method.class, Class.class);
        getMappingForMethod.setAccessible(true);
        RequestMappingInfo info = (RequestMappingInfo) getMappingForMethod.invoke(requestMappingHandlerMapping, remoteInvoke, GeneralRemoteController.class);

        requestMappingHandlerMapping.registerMapping(info, controller, remoteInvoke);

    }
}
